/*
 * @Author: error: git config user.name & please set dead value or install git
 * @Date: 2023-05-26 10:26:27
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2023-11-29 12:23:14
 * @FilePath: \stm32g431_AllRings\applications\rs485.c
 * @Description:
 *
 * Copyright (c) 2023 by ${git_name_email}, All Rights Reserved.
 */
#include "rs485.h"
#include <board.h>
// #include "srt_im.h"

#define DBG_TAG "rs485"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include "iap_para.h"

#define DEV_RS485 "uart2"

//#define RS485_REN_PIN GET_PIN(B, 11) // 匹配电阻使能
//#define RS485_RE_PIN GET_PIN(B, 4)

//#define RS485_REN_DISEN() rt_pin_write(RS485_REN_PIN, PIN_HIGH) // 失能匹配电阻
//#define RS485_REN_EN() rt_pin_write(RS485_REN_PIN, PIN_LOW)  // 使能匹配电阻

//#define RS485_TX_EN() rt_pin_write(RS485_RE_PIN, PIN_HIGH)
//#define RS485_RX_EN() rt_pin_write(RS485_RE_PIN, PIN_LOW)

/*device*/
rt_device_t dev_rs485; //= RT_NULL;

/*thread*/
#define THREAD_STACK_RS485_RX 1024
#define THREAD_PRIO_RS485_RX 25
static rt_thread_t rs485_app = RT_NULL;
/*mutex*/
static rt_mutex_t rs485_cmd_mutex = RT_NULL;
/*sem*/;
static rt_sem_t rs485_rx_sem = RT_NULL;
/*ringbuffer*/
#define USERINGBUFF
#ifdef USERINGBUFF
struct rt_ringbuffer ringbuffer_rs485rx_rollup; // 创建环形缓冲，用于存储brg-串口接收数据
rt_uint8_t rbpool_rs485rx_rollup[1 * 1024];     // 创建环形缓冲池
#endif

uint8_t ctx_send_buf[AGILE_MODBUS_MAX_ADU_LENGTH];
uint8_t ctx_read_buf[AGILE_MODBUS_MAX_ADU_LENGTH];

agile_modbus_rtu_t ctx_rtu;
agile_modbus_t *ctx = &ctx_rtu._ctx;

#if 1

static rt_err_t rs485_ind_cb(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(rs485_rx_sem);

    return RT_EOK;
}

int rs485_send(uint8_t *buf, int len)
{
    RS485_TX_EN();
	rt_hw_us_delay(500);
    rt_device_write(dev_rs485, 0, buf, len);
	rt_hw_us_delay(100);	
    RS485_RX_EN();

    return len;
}

int rs485_receive(uint8_t *buf, int bufsz, int timeout, int bytes_timeout)
{
    int len = 0;

    rt_sem_control(rs485_rx_sem, RT_IPC_CMD_RESET, RT_NULL);

    while (1)
    {
        int rc = rt_device_read(dev_rs485, 0, buf + len, bufsz);
        if (rc > 0)
        {
            timeout = bytes_timeout;
            len += rc;
            bufsz -= rc;
            if (bufsz == 0)
                break;

            continue;
        }

        if (rt_sem_take(rs485_rx_sem, rt_tick_from_millisecond(timeout)) != RT_EOK)
            break;
        timeout = bytes_timeout;
    }

    return len;
}

int rs485_pass(rt_uint8_t *send_buf, int send_len, rt_uint8_t *read_buf, int read_bufsz, int timeout, int bytes_timeout)
{
    if ((send_buf == RT_NULL) || (send_len <= 0) || (read_buf == RT_NULL) || (read_bufsz <= 0) || (timeout <= 0))
        return -RT_ERROR;

    rs485_send(send_buf, send_len);
    int read_len = rs485_receive(read_buf, read_bufsz, timeout, bytes_timeout);

    return read_len;
}

int rs485_init(void)
{
    rt_pin_mode(RS485_REN_PIN, PIN_MODE_OUTPUT);
    RS485_REN_DISEN(); // 默认关闭匹配电阻

    rt_pin_mode(RS485_RE_PIN, PIN_MODE_OUTPUT);
    RS485_RX_EN();

    rs485_rx_sem = rt_sem_create("rs485", 0, RT_IPC_FLAG_FIFO);
    if (rs485_rx_sem == RT_NULL)
    {
        LOG_E("create rx_sem failed.");
        return -RT_ERROR;
    }
                       
    dev_rs485 = rt_device_find("uart2");
    if (dev_rs485 == RT_NULL)
    {
        LOG_E("can't find device uart2.");
        rt_sem_delete(rs485_rx_sem);
        return -RT_ERROR;
    }
    else
    {
        struct serial_configure xconfig = RT_SERIAL_CONFIG_DEFAULT;

        // extern union union_sys_savepara allrings_paras;
        switch (allrings_paras.allsys_para.rings_devices)
        {
        case RINGS_RS485_SRT_IM:
            xconfig.baud_rate = BAUD_RATE_38400;
            break;
        case RINGS_RS485_EPG_XX:
            xconfig.baud_rate = BAUD_RATE_115200;
            break;
        default:
            xconfig.baud_rate = BAUD_RATE_115200;
            break;
        }

        // BAUD_RATE_38400;
        //  xconfig.bufsz = 256;
        rt_device_control(dev_rs485, RT_DEVICE_CTRL_CONFIG, &xconfig); // 配置uart2
    }

    rt_device_set_rx_indicate(dev_rs485, rs485_ind_cb);
    rt_device_open(dev_rs485, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);

    return RT_EOK;
}

void rs485_main_entry(void *parameter)
{
    while (1)
    {
        // SRT_R_COILS_CLEAR_CTR();
        // rt_thread_mdelay(20);
        // SRT_R_INPUTREG_RTP();
        rt_thread_mdelay(200);
    }
}

int agile_modbusrtu(void)
{
    rs485_init();

    agile_modbus_rtu_init(&ctx_rtu, ctx_send_buf, sizeof(ctx_send_buf), ctx_read_buf, sizeof(ctx_read_buf));

    switch (allrings_paras.allsys_para.rings_devices)
    {
    case RINGS_RS485_SRT_IM:
        agile_modbus_set_slave(ctx, 1);
        break;
    case RINGS_RS485_EPG_XX:
        agile_modbus_set_slave(ctx, 9);
        break;
    default:
        agile_modbus_set_slave(ctx, 1);
        break;
    }

    LOG_I("agile modbus running...");

    /*	create  thread    */
    rs485_app = rt_thread_create("modbus", rs485_main_entry, RT_NULL,
                                 THREAD_STACK_RS485_RX, THREAD_PRIO_RS485_RX, 50);

    if (rs485_app == RT_NULL)
    {
        LOG_E("modbus_analasis thread create failed! \r\n");
        return RT_ERROR;
    }
    else
        rt_thread_startup(rs485_app); // 启动线程

    return RT_EOK;
}
INIT_APP_EXPORT(agile_modbusrtu);

#else

struct rt_messagequeue rs485_rx_mq; // 定义消息队列结构体
/*messegequeue---pool*/
ALIGN(RT_ALIGN_SIZE)
uint8_t rs485_rxmq_pool[2 * 1024] = {0}; // 接收消息队列池

struct rs485_msg
{
    rt_device_t dev;
    rt_size_t size;
};

/* rs485-uart2 receive data feedback */
rt_err_t rs485_rx_feedback(rt_device_t dev, rt_size_t size)
{
    rt_err_t sta = RT_EOK;

    struct rs485_msg rx_smsg;

    rx_smsg.dev = dev;
    rx_smsg.size = size;

    sta = rt_mq_send(&rs485_rx_mq, &rx_smsg, sizeof(rx_smsg)); // 发送消息队列

    if (sta == -RT_EFULL)
    {
        LOG_E("messege queue is full!\r\n");
    }

    return sta;
}

uint8_t rx_buff[RT_SERIAL_RB_BUFSZ + 1] = {0};
void tbridge_rx_entry(void *parameter)
{
    uint16_t rx_length = 0;
    struct rs485_msg rx_msg;

    rt_memset(&rx_msg, 0, sizeof(rx_msg));

    while (1)
    {
        rt_mq_recv(&rs485_rx_mq, &rx_msg, sizeof(rx_msg), RT_WAITING_FOREVER);

        rx_length = rt_device_read(rx_msg.dev, 0, &rx_buff[0], rx_msg.size);
    }
}

int rs485_init(void)
{
    rt_err_t rt_sta = RT_EOK;

    rt_thread_t trs485_analasis = RT_NULL;
    rt_thread_t trs485_receive = RT_NULL;
    rt_thread_t trs485_send = RT_NULL;

    rt_pin_mode(RS485_REN_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(RS485_REN_PIN, PIN_LOW); // 默认关闭匹配电阻

    serial_rs485 = rt_device_find(DEV_RS485); // 获取u2设备

    if (serial_rs485 == RT_NULL)
    {
        LOG_E("uart2 device find failed!\r\n");
        return rt_sta = RT_ERROR;
    }
    else
    {
        struct serial_configure xconfig = RT_SERIAL_CONFIG_DEFAULT;

        xconfig.baud_rate = 500000; // BAUD_RATE_2000000;
        // xconfig.bufsz = 256;

        rt_device_control(serial_rs485, RT_DEVICE_CTRL_CONFIG, &xconfig); // 重新配置uart2
    }
    /*	init semaphore	*/
    // rt_sem_init(&rs485_rx_sem,"brg_sem",0,RT_IPC_FLAG_FIFO);
    /*	config  messege queue	*/
    rt_mq_init(&rs485_rx_mq, "rs485_mq",
               rs485_rxmq_pool,          /* 存放消息的缓冲区 */
               sizeof(struct rs485_msg), /* 一条消息的最大长度 */
               sizeof(rs485_rxmq_pool),  /* 存放消息的缓冲区大小 */
               RT_IPC_FLAG_FIFO);        /* 如果有多个线程等待，按照先来先得到的方法分配消息 */

    rt_device_open(serial_rs485, RT_DEVICE_FLAG_DMA_RX); // dma接收

    rt_device_set_rx_indicate(serial_rs485, rs485_rx_feedback); // 设置接收回调函数

    /*create rs485 cmd mutex*/
    rs485_cmd_mutex = rt_mutex_create("fd_cmd", RT_IPC_FLAG_PRIO); // 按照优先级互斥，使用过程中，以上层命令优先
    if (rs485_cmd_mutex == RT_NULL)
        return rt_sta = RT_ERROR;

    /*	create rs485 thread	*/
    trs485_receive = rt_thread_create("trs485_rx", trs485_rx_entry, RT_NULL,
                                      THREAD_STACK_RS485_RX, THREAD_PRIO_RS485_RX, 20);

    rt_ringbuffer_init(&ringbuffer_brgrx_rollup, rbpool_brgrx_rollup, sizeof(rbpool_brgrx_rollup)); // 创建brg接收环形缓冲
    rt_ringbuffer_init(&ringbuffer_brgtx_rollup, rbpool_brgtx_rollup, sizeof(rbpool_brgtx_rollup)); // 创建brg发送环形缓冲

    if (trs485_analasis == RT_NULL || trs485_receive == RT_NULL)
    {
        LOG_E("trs485 thread create failed! \r\n");
        return rt_sta = RT_ERROR;
    }
    else
    {
        rt_thread_startup(trs485_receive);  // 启动线程
        rt_thread_startup(trs485_analasis); // 启动线程
        rt_thread_startup(trs485_send);     // 启动线程
    }
    return rt_sta = RT_EOK;
}
#endif
